#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>

#include "zcap.h"

typedef struct{
    int rspDone;
    char ask[255];
    char rsp[255];
}CfgFmt;

static void printchs(const char *str,int begin,int end)
{
    int i=0;

    for(i=begin;i<end;i++){
        ZCAP_LOGPD("%c",str[i]);
    }
    ZCAP_LOGPD("\n");
}

static int CfgInit(const char *cfgfname,CfgFmt **pcfgFmts,int *cfgnum)
{
    int err=-1;
    FILE *fp=fopen(cfgfname,"rt");
    char linebuf[255];
    int maxLine=255,lineCnt=0;
    int askLen=0,rspLen=0;
    char *rsp=NULL;
    CfgFmt *CfgFmts=NULL;
    CfgFmt *cfgFmt=NULL;

    memset(linebuf,0,sizeof(linebuf));
    while(fgets(linebuf,sizeof(linebuf),fp)){
        if('#'==linebuf[0]){
            memset(linebuf,0,sizeof(linebuf));
            continue;
        }
        if(!strncmp("MaxLine=",linebuf,strlen("MaxLine="))){
            if(1==sscanf(linebuf,"MaxLine=%d",&maxLine)){
                //ZCAP_LOGD("p maxLine=%d\n",maxLine);
                if(maxLine>0){
                    if(CfgFmts){
                        free(CfgFmts);
                        CfgFmts=NULL;
                    }
                    CfgFmts=(CfgFmt *)calloc(1,sizeof(CfgFmt)*maxLine);
                    if(!CfgFmts){
                        err=-2;
                    }
                }
            }
        }
        else if(!strncmp("ASK=",linebuf,strlen("ASK="))){
            if((rsp=strstr(linebuf,"RSP="))){
                if(CfgFmts&&(lineCnt<maxLine)){
                    askLen=rsp-linebuf;
                    rspLen=linebuf+strlen(linebuf)-rsp;
                    if(askLen<255&&rspLen<255){
                        cfgFmt=&CfgFmts[lineCnt];
                        memcpy(cfgFmt->ask,linebuf+4,askLen-4);
                        memcpy(cfgFmt->rsp,rsp    +4,rspLen-4);
                        //ZCAP_LOGD("ask: %s\n",cfgFmt->ask);
                        //ZCAP_LOGD("rsp: %s\n",cfgFmt->rsp);
                        lineCnt++;
                        err=0;
                    }
                }
            }
        }
        memset(linebuf,0,sizeof(linebuf));
    }
    fclose(fp);

    *pcfgFmts=CfgFmts;
    *cfgnum=lineCnt;
    return err;
}

static void CfgUninit(CfgFmt **pcfgFmts)
{
    if(*pcfgFmts){
        free(*pcfgFmts);
        *pcfgFmts=NULL;
    }
}

int zcapf(const char *cfgfname,const char* cmd, const char* argv[])
{
    int err=0,ret=0;
    CfgFmt *CfgFmts=NULL;
    int cfgFmtCnt=0,cfgidx=0;
    int pty=0,slave=0;
    char ptyName[1024];

    pid_t pid;

    char frxbuf[1024];

    ZCAP_LOGD("cfgfname: %s\n",cfgfname);
    ZCAP_LOGD("cmd: %s\n",cmd);

    if(CfgInit(cfgfname,&CfgFmts,&cfgFmtCnt)){
        ZCAP_LOGF("CfgInit err %s\n",strerror(errno));
        return -3;
    }

    if(openpty(&pty,&slave,ptyName,NULL,NULL)<0){
        ZCAP_LOGF("openpty err %s\n",strerror(errno));
        return -4;
    }

    ZCAP_LOGD("start cmd\n");

    pid=fork();
    if(pid<0){
        ZCAP_LOGF("fork err %s\n",strerror(errno));
        return -1;
    }
    if(!pid){
        err=0;
        close(pty);
        login_tty(slave);

        if(execvp(argv[0],argv)){
            ZCAP_LOGF("%s exe err %s\n",argv[0],strerror(errno));
            err=-4;
            goto C_ERR_RETURN1;
        }

C_ERR_RETURN1:
        return err;
    }
    close(slave);

    int usedRxBufLen=0;
    memset(frxbuf,0,sizeof(frxbuf));
    while(1){
        ret=read(pty,frxbuf+usedRxBufLen,sizeof(frxbuf)-usedRxBufLen);
        if(ret<0){
            //ZCAP_LOGF("read err %s\n",argv[0],strerror(errno));
            break;
        }
        else if(!ret){
            //ZCAP_LOGF("cmd finished\n");
            break;
        }

        ZCAP_LOGPD("%s",frxbuf+usedRxBufLen);

        for(cfgidx=0;cfgidx<cfgFmtCnt;cfgidx++){
            if(CfgFmts[cfgidx].rspDone){
                continue;
            }
            if(strstr(frxbuf,CfgFmts[cfgidx].ask)){
//                ZCAP_LOGPD("rsp:%s\n",CfgFmts[cfgidx].rsp);
                write(pty,CfgFmts[cfgidx].rsp,strlen(CfgFmts[cfgidx].rsp));
                write(pty,"\n",1);
                CfgFmts[cfgidx].rspDone=1;
            }
        }

        if('\n'==frxbuf[strlen(frxbuf)-1]){
            memset(frxbuf,0,sizeof(frxbuf));
            usedRxBufLen=0;
        }
        else{
            usedRxBufLen+=strlen(frxbuf);
            if(sizeof(frxbuf)<=usedRxBufLen){
                memset(frxbuf,0,sizeof(frxbuf));
                usedRxBufLen=0;
            }
        }
    }

    CfgUninit(&CfgFmts);

    return err;
}

